﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace PrimitiveEngine.Primitives
{
    public class PECircle : PEPrimitive
    {
        public float Radius;

        public override int PrimitiveCount { get { return primitiveCount; } }

        private static Vector3[] tempArray1 = new Vector3[slices];
        private static Vector3[] tempArray2 = new Vector3[slices];

        private int primitiveCount = 0;

        private const int slices = 32;

        #region Circle Identity Coordinates

        private static Vector3[] circleIdentityCoords = new Vector3[] { 
            new Vector3(0.5000f, 0.0000f, 0f),
            new Vector3(0.4904f, 0.0975f, 0f),
            new Vector3(0.4619f, 0.1913f, 0f),
            new Vector3(0.4157f, 0.2778f, 0f),
            new Vector3(0.3536f, 0.3536f, 0f),
            new Vector3(0.2778f, 0.4157f, 0f),
            new Vector3(0.1913f, 0.4619f, 0f),
            new Vector3(0.0975f, 0.4904f, 0f),
            new Vector3(0.0000f, 0.5000f, 0f),
            new Vector3(-0.0975f, 0.4904f, 0f),
            new Vector3(-0.1913f, 0.4619f, 0f),
            new Vector3(-0.2778f, 0.4157f, 0f),
            new Vector3(-0.3536f, 0.3536f, 0f),
            new Vector3(-0.4157f, 0.2778f, 0f),
            new Vector3(-0.4619f, 0.1913f, 0f),
            new Vector3(-0.4904f, 0.0975f, 0f),
            new Vector3(-0.5000f, 0.0000f, 0f),
            new Vector3(-0.4904f, -0.0975f, 0f),
            new Vector3(-0.4619f, -0.1913f, 0f),
            new Vector3(-0.4157f, -0.2778f, 0f),
            new Vector3(-0.3536f, -0.3536f, 0f),
            new Vector3(-0.2778f, -0.4157f, 0f),
            new Vector3(-0.1913f, -0.4619f, 0f),
            new Vector3(-0.0975f, -0.4904f, 0f),
            new Vector3(0.0000f, -0.5000f, 0f),
            new Vector3(0.0975f, -0.4904f, 0f),
            new Vector3(0.1913f, -0.4619f, 0f),
            new Vector3(0.2778f, -0.4157f, 0f),
            new Vector3(0.3536f, -0.3536f, 0f),
            new Vector3(0.4157f, -0.2778f, 0f),
            new Vector3(0.4619f, -0.1913f, 0f),
            new Vector3(0.4904f, -0.0975f, 0f),
        };

        #endregion

        public PECircle()
        {
            Type = PEPrimitiveType.Circle;
        }

        public PECircle(Vector2 center, float radius)
        {
            Type = PEPrimitiveType.Circle;
            Position = center;
            Radius = radius;
            BorderColor = Color.White;
            BorderWidth = 10.0f;
        }

        public PECircle(Vector2 center, float radius, Color color)
        {
            Type = PEPrimitiveType.Circle;
            Position = center;
            Radius = radius;
            BorderColor = color;
            BorderWidth = 10.0f;
        }

        public PECircle(Vector2 center, float radius, float layer, Color color)
        {
            Type = PEPrimitiveType.Circle;
            Position = center;
            Radius = radius;
            Layer = layer;
            FillColor = color;
            IsFilled = true;
            BorderColor = Color.Black; ;
            BorderWidth = 1;
        }

        public override bool Intersection(PEPrimitive primitive)
        {
            throw new NotImplementedException();
        }

        public override bool Inside(Vector2 point)
        {
            throw new NotImplementedException();
        }

        public override void CreateUV()
        {
            throw new NotImplementedException();
        }

        public override void Draw(ref VertexPositionColorTexture[] vertices, ref int vertexIndex, ref short[] indices, ref int indiceIndex)
        {
            Matrix mat = Matrix.CreateScale(Radius * 2f - BorderWidth * 2) * Matrix.CreateTranslation(new Vector3(Position, -Layer));

            Vector3.Transform(circleIdentityCoords, ref mat, tempArray2);

            primitiveCount = 0;

            if (IsFilled)
            {
                // create a center vertex
                vertices[vertexIndex].Position = new Vector3(Position, -Layer);
                vertices[vertexIndex].Color = FillColor;
                vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                short centerIndex = (short)vertexIndex;
                vertexIndex++;

                for (int i = 1; i < slices; i++)
                {
                    vertices[vertexIndex].Position = tempArray2[i - 1];
                    vertices[vertexIndex].Color = FillColor;
                    vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                    vertexIndex++;

                    vertices[vertexIndex].Position = tempArray2[i];
                    vertices[vertexIndex].Color = FillColor;
                    vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                    vertexIndex++;

                    indices[indiceIndex++] = centerIndex;
                    indices[indiceIndex++] = (short)(vertexIndex - 2);
                    indices[indiceIndex++] = (short)(vertexIndex - 1);

                    primitiveCount++;
                }

                indices[indiceIndex++] = centerIndex;
                indices[indiceIndex++] = (short)(vertexIndex - 1);
                indices[indiceIndex++] = (short)(centerIndex + 1);

                primitiveCount++;
            }

            if (BorderWidth > 0)
            {
                mat = Matrix.CreateScale(Radius * 2f) * Matrix.CreateTranslation(new Vector3(Position, -Layer));

                Vector3.Transform(circleIdentityCoords, ref mat, tempArray1);

                for (int i = 0; i < slices; i++)
                {
                    int index = vertexIndex;
                    // 0
                    vertices[vertexIndex].Position = tempArray1[i];
                    vertices[vertexIndex].Color = BorderColor;
                    vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                    vertexIndex++;
                    // 1
                    vertices[vertexIndex].Position = tempArray2[i];
                    vertices[vertexIndex].Color = BorderColor;
                    vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                    vertexIndex++;
                    // 2
                    if (i == slices - 1)
                    {
                        vertices[vertexIndex].Position = tempArray1[0];
                        vertices[vertexIndex].Color = BorderColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;
                        // 3
                        vertices[vertexIndex].Position = tempArray2[0];
                        vertices[vertexIndex].Color = BorderColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;
                    }
                    else
                    {
                        vertices[vertexIndex].Position = tempArray1[i + 1];
                        vertices[vertexIndex].Color = BorderColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;
                        // 3
                        vertices[vertexIndex].Position = tempArray2[i + 1];
                        vertices[vertexIndex].Color = BorderColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;
                    }

                    indices[indiceIndex++] = (short)(index + 0);
                    indices[indiceIndex++] = (short)(index + 2);
                    indices[indiceIndex++] = (short)(index + 1);

                    indices[indiceIndex++] = (short)(index + 2);
                    indices[indiceIndex++] = (short)(index + 3);
                    indices[indiceIndex++] = (short)(index + 1);

                    primitiveCount += 2;
                }
            }
        }
    }
}
